package com.service.screenReception.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.service.config.utils.IdUtil;
import com.service.config.utils.RedisUtil;
import com.service.screenReception.dao.ScreenUserDao;
import com.service.screenReception.dto.*;
import com.service.screenReception.entity.ScreenUser;
import com.service.screenReception.service.TopoService;
import com.service.screenReception.task.CloudCampusApi;
import com.service.screenReception.task.ScheduleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import static com.service.config.constant.ApiUrlConstants.DEVICES_URL;
import static com.service.config.constant.ApiUrlConstants.LINK_AGGREGATION;

@Service
@Slf4j
public class TopoServiceImpl implements TopoService {
    @Resource
    RestTemplate restTemplate;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private CloudCampusApi cloudCampusApi;
    @Autowired
    ScheduleService scheduleService;
    @Resource
    ScreenUserDao screenUserDao;

    //链路集合
    public static List<LinkInfoDto> linkList;
    //所有链路中设备(去重后)集合
    public static List<TopoInfoDto> deviceList;
    //云平台查询的所有设备集合
    private static List<TopoInfoDto> cloudDeviceList;
    //某树下所有设备节点
    private static Set<TopoInfoDto> deviceEntityList;
    //所有树的集合(树结构未确定，仅包含树中的所有设备)
    private static List<TreeInfoDto> trees;
    //AP设备集合
    private static Set<TopoInfoDto> APList;
    //查到对应设备后收集该设备，再通过该设备的源设备、北向设备查询其他连接设备
    static List<LinkInfoDto> collectLink;
    //暂存对端设备，通过其再查询到其的对端设备，完成层高遍历
    private static List<TopoInfoDto> labelDeviceList;
    //两个设备多条链路连接标志
    final double[] linkSign = {0.2,-0.2,0.4,-0.4,0.6,-0.6,0.8,-0.8,0};
    private Map<Object,Object> topoData;
    private Map<Object,Object> topoDataMap;


    @Override
    public Map<Object, Object> getTopo(UserDto userDto) {
        this.init();
        Map<Object, Object> cloudData = this.getCloudData(userDto);
        if (null == cloudData)
        {
            return null;
        }
        return cloudData;
    }

    /**
     * 容器初始化
     */
    public void init()
    {
        APList = new HashSet<>();
        trees = new ArrayList<>();
        deviceList = new ArrayList<>();
        linkList = new ArrayList<>();
        collectLink = new ArrayList<>();
        cloudDeviceList = new ArrayList<>();
        labelDeviceList = new ArrayList<>();
    }

    /**
     * 获取云平台数据
     * @param userDto
     * @return
     */
    public Map<Object,Object> getCloudData(UserDto userDto)
    {
        ScreenUser screenUser = new ScreenUser();
        screenUser.setUserId(userDto.getId());
        List<ScreenUser> screenUsers = screenUserDao.queryAll(screenUser);
        boolean flag = false;

        //缓存中有设备数据
        if (redisUtil.get(userDto.getId().concat("_cloudDeviceList")) != null)
        {
            flag=true;
            cloudDeviceList = (List<TopoInfoDto>) redisUtil.get(userDto.getId().concat("_cloudDeviceList"));
        }

        if(screenUsers.size()>0)
        {
            for (ScreenUser user : screenUsers) {
                if (user.getDomain() == null || "".equals(user.getDomain())) {
                    user.setDomain("naas");
                }

                HttpHeaders requestHeaders = this.getHeader(user.getTenantName(), user.getTenantPwd(),user.getDomain());
                if (flag == false)
                {
                    List<TopoInfoDto> devices = this.getDevices(requestHeaders,user.getDomain());
                    cloudDeviceList.addAll(devices);
                }

                try {
                    HttpEntity<String> requestEntity = new HttpEntity<>(requestHeaders);
                    ResponseEntity<JSONObject> response = restTemplate.exchange("https://"+user.getDomain()+LINK_AGGREGATION , HttpMethod.GET, requestEntity, JSONObject.class);
                    JSONArray data = response.getBody().getJSONArray("data");
                    linkList.addAll(data.toJavaList(LinkInfoDto.class));
                } catch (Exception e) {
                    log.error("debug getLinks ==>" + e.getMessage());
                }
            }
            if (flag == false)
            {
                redisUtil.sets(userDto.getId().concat("_cloudDeviceList"),cloudDeviceList,12L);
            }
            if(linkList.size()==0)
            {
                return null;
            }
        }else {
            return null;
        }

        try {
            stepOne();
            stepTwo();
            topoData = packageData();
            return topoData;
        }catch (Exception e)
        {
            log.error("data hand error"+e.getMessage());
            return null;
        }
    }

    /**
     * 封装数据
     * @return
     */
    public Map<Object, Object> packageData()
    {
        //封装数据一
        List<Map<String,String>> finalTypeList = new ArrayList<>();
        Map<String,String> typeMap;
        int maxLevel = deviceList.get(0).getStorey().get(0);
        for (TopoInfoDto device : deviceList) {
            if(device.getStorey().get(0) > maxLevel)
            {
                maxLevel = device.getStorey().get(0);
            }
        }
        for (int i=0;i<maxLevel;i++) {
            typeMap = new LinkedHashMap<>();
            typeMap.put("name","level_"+(i+1));
            if(i == 0)
            {
                typeMap.put("symbol","image://");
            }else {
                typeMap.put("symbol","image://");
            }
            finalTypeList.add(typeMap);
        }


        //为每个设备赋X、Y坐标位置(前端设备坐标位置)
        Map<String, Integer> map ;
        List<TopoInfoDto> list;
        Map<String,List<TopoInfoDto>> deviceMap;
        int treeLabel = 0;
        for (TreeInfoDto tree : trees) {
            Set<TopoInfoDto> totalNodesOfTree = tree.getTotalNodesOfTree();
            int mxLevel = 0;
            for (TopoInfoDto TopoInfoDto : totalNodesOfTree) {
                if(TopoInfoDto.getStorey().get(0)>mxLevel)
                {
                    mxLevel=TopoInfoDto.getStorey().get(0);
                }
            }

            map = new HashMap();
            deviceMap = new HashMap<>();
            for(int i=1;i<=maxLevel;i++)
            {
                list = new ArrayList<>();
                int count = 0;
                for (TopoInfoDto device : totalNodesOfTree) {
                    if(device.getStorey().get(0) == i)
                    {
                        count++;
                        list.add(device);
                        map.put(tree.getId()+"_"+i,count);
                    }
                    deviceMap.put(tree.getId()+"_"+i,list);
                }
            }

            for (Iterator iterator = totalNodesOfTree.iterator();iterator.hasNext();) {
                TopoInfoDto next = (TopoInfoDto) iterator.next();
                int level = next.getStorey().get(0);
                //每层有多少个设备
                Integer count = map.get(tree.getId()+"_"+level);
                List<TopoInfoDto> TopoInfoDtos = deviceMap.get(tree.getId() + "_" + level);
                int treeWidth = 3600/(trees.size());
                int treeX = (treeWidth)*treeLabel;
                for (int k=0;k<TopoInfoDtos.size();k++) {
                    int deviceWidth=treeWidth/(TopoInfoDtos.size()+1);
                    TopoInfoDtos.get(k).setX(treeX+deviceWidth*(k+1));
                }
                next.setY(((mxLevel-level)+1)*(2200/(mxLevel+1)));
            }
            treeLabel++;
        }

        //封装数据二
        List<TopoInfoDto> dataList = new ArrayList<>();
        for (TopoInfoDto device : deviceList) {
            device.setCategory(device.getStorey().get(0)-1);
            dataList.add(device);
        }

        //封装数据三
        Map<String,Object> linkMap;
        Map<String,Object> lineMap;
        Map<String,Double> normalMap;
        List<Map<String,Object>> linkDataList = new ArrayList<>();

        String aPortName = "";
        String zPortName = "";

        List<LinkInfoDto> copyLinkList = new ArrayList<>();
        for (LinkInfoDto link : linkList) {
            copyLinkList.add(link);
        }
        for (LinkInfoDto link : linkList) {
            int sign=0;
            linkMap = new HashMap<>();
            lineMap = new HashMap<>();
            normalMap = new HashMap<>();

            aPortName=link.getAPortName();
            zPortName=link.getZPortName();

            linkMap.put("speed",link.getSpeed());
            linkMap.put("source",link.getAneDn());
            linkMap.put("target",link.getZneDn());
            linkMap.put("aneIp",link.getAneIp());
            linkMap.put("aportName",this.concatString(aPortName));
            linkMap.put("zneIp",link.getZneIp());
            linkMap.put("zportName",this.concatString(zPortName));
            linkMap.put("aneDn",link.getAneDn());
            linkMap.put("zneDn",link.getZneDn());
            for (LinkInfoDto linkInfoDto : linkList) {
                if (link.getAneDn().equals(linkInfoDto.getAneDn()) && link.getZneDn().equals(linkInfoDto.getZneDn()) && link!=linkInfoDto && copyLinkList.contains(linkInfoDto))
                {
                    if (sign == 0)
                    {
                        lineMap = new HashMap<>();
                        normalMap = new HashMap<>();
                        normalMap.put("curveness",linkSign[0]);
                        lineMap.put("normal",normalMap);
                        linkMap.put("lineStyle",lineMap);
                        sign++;
                        linkDataList.add(linkMap);
                        copyLinkList.remove(link);
                    }

                    linkMap = new HashMap<>();
                    lineMap = new HashMap<>();
                    normalMap = new HashMap<>();
                    aPortName=linkInfoDto.getAPortName();
                    zPortName=linkInfoDto.getZPortName();

                    linkMap.put("speed",linkInfoDto.getSpeed());
                    linkMap.put("source",linkInfoDto.getAneDn());
                    linkMap.put("target",linkInfoDto.getZneDn());
                    linkMap.put("aneIp",linkInfoDto.getAneIp());
                    linkMap.put("aportName",this.concatString(aPortName));
                    linkMap.put("zneIp",linkInfoDto.getZneIp());
                    linkMap.put("zportName",this.concatString(zPortName));
                    linkMap.put("aneDn",linkInfoDto.getAneDn());
                    linkMap.put("zneDn",linkInfoDto.getZneDn());

                    normalMap.put("curveness",linkSign[sign]);
                    lineMap.put("normal",normalMap);
                    linkMap.put("lineStyle",lineMap);
                    copyLinkList.remove(linkInfoDto);
                    sign++;

                    linkDataList.add(linkMap);
                    continue;
                }
            }
            if(copyLinkList.contains(link))
            {
                normalMap.put("curveness", (double) 0);
                lineMap.put("normal",normalMap);
                linkMap.put("lineStyle",lineMap);
                linkDataList.add(linkMap);
            }
        }

        topoData = new LinkedHashMap<>();

        topoDataMap = new HashMap<>();
        topoData.put("categories",finalTypeList);

        topoDataMap = new HashMap<>();
        topoData.put("data",dataList);

        topoDataMap = new HashMap<>();
        topoData.put("links",linkDataList);
        return topoData;
    }

    /**
     * 缩写端口
     * @param content
     * @return
     */
    public String concatString(String content)
    {
        if (content.contains("XGigabitEthernet"))
        {
            content = "XGE "+content.substring(16);
        }else if(content.contains("Ten-GigabitEthernet"))
        {
            content = "10GE "+content.substring(19);
        }else if(content.contains("GigabitEthernet"))
        {
            content = "GE "+content.substring(15);
        }else if(content.contains("Ethernet"))
        {
            content = "Eth "+ content.substring(8);
        }
        return content;
    }

    /**
     * 步骤一：遍历获取所有链路中包含的设备，跟云平台设备数据对比，确定设备的具体信息，并且获取此条链路的部分信息存入topoInfoDto对象的map集合；(如果没有从云设备数据中获取到相关设备数据，则根据链路中的设备信息，创建两个设备对象)
     * 步骤二:将上一步获取的设备集合去重；
     * 步骤三：给链路Entity确定源设备和北向设备；
     * 步骤四：设置对端设备ID列表
     */
    public void stepOne()
    {
        //①遍历获取所有链路中包含的设备；
        TopoInfoDto deviceEntity=null;
        boolean flag1 = false;
        boolean flag2 = false;

        for(LinkInfoDto link:linkList)
        {
            for (TopoInfoDto cloudDevice : cloudDeviceList) {
                if (link.getAneDn().equals(cloudDevice.getId())) {
                    cloudDevice.getAPortName().put(cloudDevice.getId().concat("_").concat(link.getZneDn()),link.getAPortName());
                    cloudDevice.getAPortIp().put(cloudDevice.getId().concat("_").concat(link.getZneDn()),link.getAneIp());
                    cloudDevice.getZPortName().put(link.getZneDn().concat("_").concat(cloudDevice.getId()),link.getZPortName());
                    cloudDevice.getZPortIp().put(link.getZneDn().concat("_").concat(cloudDevice.getId()),link.getZneIp());
                    deviceList.add(cloudDevice);
                    flag1 = true;
                    break;
                } else {
                    flag1 = false;
                }
            }
            for (TopoInfoDto cloudDevice : cloudDeviceList) {
                if(link.getZneDn().equals(cloudDevice.getId()))
                {
                    cloudDevice.getAPortName().put(link.getAneDn().concat("_").concat(cloudDevice.getId()),link.getAPortName());
                    cloudDevice.getAPortIp().put(link.getAneDn().concat("_").concat(cloudDevice.getId()),link.getAneIp());
                    cloudDevice.getZPortName().put(cloudDevice.getId().concat("_").concat(link.getAneDn()),link.getZPortName());
                    cloudDevice.getZPortIp().put(cloudDevice.getId().concat("_").concat(link.getAneDn()),link.getZneIp());
                    deviceList.add(cloudDevice);
                    flag2=true;
                    break;
                }else {
                    flag2 = false;
                }
            }
            //设备在云平台的设备数据中查不到的情况
            if(flag1 == false)
            {
                boolean sign1=false;
                for (TopoInfoDto data : deviceList) {
                    if(data.getId().equals(link.getAneDn()))
                    {
                        data.getAPortName().put(data.getId().concat("_").concat(link.getZneDn()),link.getAPortName());
                        data.getAPortIp().put(data.getId().concat("_").concat(link.getZneDn()),link.getAneIp());
                        data.getZPortName().put(link.getZneDn().concat("_").concat(data.getId()),link.getZPortName());
                        data.getZPortIp().put(link.getZneDn().concat("_").concat(data.getId()),link.getZneIp());

                        sign1=true;
                    }
                }
                if(sign1 == false)
                {
                    deviceEntity = new TopoInfoDto();
                    deviceEntity.setId(link.getAneDn());
                    deviceEntity.setName(link.getAneName());

                    deviceEntity.getAPortName().put(deviceEntity.getId().concat("_").concat(link.getZneDn()),link.getAPortName());
                    deviceEntity.getAPortIp().put(deviceEntity.getId().concat("_").concat(link.getZneDn()),link.getAneIp());
                    deviceEntity.getZPortName().put(link.getZneDn().concat("_").concat(deviceEntity.getId()),link.getZPortName());
                    deviceEntity.getZPortIp().put(link.getZneDn().concat("_").concat(deviceEntity.getId()),link.getZneIp());

                    deviceList.add(deviceEntity);
                }
            }
            if(flag2 == false)
            {
                boolean sign2 = false;
                for (TopoInfoDto data : deviceList) {
                    if(data.getId().equals(link.getZneDn()))
                    {
                        data.getAPortName().put(link.getAneDn().concat("_").concat(data.getId()),link.getAPortName());
                        data.getAPortIp().put(link.getAneDn().concat("_").concat(data.getId()),link.getAneIp());
                        data.getZPortName().put(link.getAneDn().concat("_").concat(data.getId()),link.getZPortName());
                        data.getZPortIp().put(link.getAneDn().concat("_").concat(data.getId()),link.getZneIp());

                        sign2=true;
                    }
                }
                if(sign2==false)
                {
                    deviceEntity = new TopoInfoDto();
                    deviceEntity.setId(link.getZneDn());
                    deviceEntity.setName(link.getZneName());

                    deviceEntity.getAPortName().put(link.getAneDn().concat("_").concat(deviceEntity.getId()),link.getAPortName());
                    deviceEntity.getAPortIp().put(link.getAneDn().concat("_").concat(deviceEntity.getId()),link.getAneIp());
                    deviceEntity.getZPortName().put(deviceEntity.getId().concat("_").concat(link.getAneDn()),link.getZPortName());
                    deviceEntity.getZPortIp().put(deviceEntity.getId().concat("_").concat(link.getAneDn()),link.getZneIp());

                    deviceList.add(deviceEntity);
                }
            }
        }
        //②去重、获取对端个数
        deviceList = deviceList.stream().distinct().collect(Collectors.toList());

        //③给链路集合中的源节点和北向节点赋值
        for (LinkInfoDto linkInfoDto : linkList) {
            for (TopoInfoDto TopoInfoDto : deviceList) {
                if(linkInfoDto.getAneDn().equals(TopoInfoDto.getId()))
                {
                    linkInfoDto.setAneDevice(TopoInfoDto);
                }else if(linkInfoDto.getZneDn().equals(TopoInfoDto.getId()))
                {
                    linkInfoDto.setZneDevice(TopoInfoDto);
                }
            }
        }
        //④设置对端设备ID列表
        for (TopoInfoDto device : deviceList) {
            for (LinkInfoDto link : linkList) {
                if(link.getAneDevice() == device && !device.getOppositeDeviceList().contains(link.getZneDevice().getId()))
                {
                    device.getOppositeDeviceList().add(link.getZneDevice().getId());
                }else if(link.getZneDevice() == device && !device.getOppositeDeviceList().contains(link.getAneDevice().getId()))
                {
                    device.getOppositeDeviceList().add(link.getAneDevice().getId());
                }
            }
        }
    }

    /**
     * 步骤一：将所有链路区分成多个topo结构树；
     * 步骤二：获取所有AP设备列表,并且给AP设备确定层级；
     * 步骤三：从AP开始遍历，确定大部分设备层级；
     * 步骤四：给无AP的topo结构确定层级；
     * 步骤五：给没有连接AP设备的路由器等确定层高；
     * 步骤六：给所有设备确定层高(取层高的整数集合最小值)
     */
    public static void stepTwo()
    {
        int flag=1;

        //确定所有链路生成的topo个数
        trees = getTotalDeviceOfTree(linkList);

        //获取所有AP设备列表,并且给AP设备确定层级 storey=1
        for(TreeInfoDto tree:trees)
        {
            Set<TopoInfoDto> totalNodes = tree.getTotalNodesOfTree();
            Iterator<TopoInfoDto> iterator = totalNodes.iterator();
            while (iterator.hasNext())
            {
                TopoInfoDto next = iterator.next();
                if(next.getDeviceType()!=null && next.getDeviceType().contains("AP") && !next.getDeviceModel().contains("AD"))
                {
                    next.getStorey().add(flag);
                    APList.add(next);
                }
            }
        }

        //从AP开始遍历，确定大部分设备层级
        List<TopoInfoDto> tempDeviceList;
        for (TopoInfoDto ap:APList)
        {
            tempDeviceList = new ArrayList<>();
            storeyRecursion(ap,flag,tempDeviceList);
        }

        //给无AP的topo结构确定层级
        for (TreeInfoDto tree : trees) {
            boolean sign = false;
            Set<TopoInfoDto> nodesOfTree = tree.getTotalNodesOfTree();
            for (TopoInfoDto TopoInfoDto : nodesOfTree) {
                if(TopoInfoDto.getStorey().size() > 0)
                {
                    sign=true;
                    break;
                }
            }
            if(false==sign)
            {
                noApStoreyConfirm(nodesOfTree);
            }
        }

        //给无AP的路由器确定层高
        for (TopoInfoDto entity : deviceList) {
            if(entity.getStorey().size() == 0)
            {
                for (LinkInfoDto link : linkList) {
                    if(link.getAneDevice() == entity)
                    {
                        List<Integer> storeysList = link.getZneDevice().getStorey();
                        Integer min = Collections.min(storeysList).intValue()+1;
                        entity.getStorey().add(min);
                    }
                }
            }
        }
        //确定每个设备层高
        confirmStorey();
    }

    /**
     * 给无AP的topo结构确定层级
     * @param nodesOfTree 所有链路包含的设备中，还没有确定层高的设备
     */
    public static void noApStoreyConfirm(Set<TopoInfoDto> nodesOfTree)
    {
        int flag=1;
        List<TopoInfoDto> leafNodes= new ArrayList<>();
        for (TopoInfoDto device : nodesOfTree) {
            boolean sign = true;
            for (LinkInfoDto link1 : linkList) {
                if(link1.getZneDevice() == device)
                {
                    sign=false;
                    break;
                }
            }
            if (sign)
            {
                leafNodes.add(device);
            }
        }
        leafNodes = leafNodes.stream().distinct().collect(Collectors.toList());
        List<TopoInfoDto> signDeviceList;
        for (TopoInfoDto leafNode : leafNodes) {
            signDeviceList=new ArrayList<>();
            leafNode.getStorey().add(flag);
            storeyRecursion(leafNode,flag,signDeviceList);
        }
    }

    /**
     * 遍历链路，获取该链路生成的每个树下的所有节点
     * @param linkList
     * @return
     */
    public static List<TreeInfoDto> getTotalDeviceOfTree(List<LinkInfoDto> linkList)
    {
        List<LinkInfoDto> copyedLinkList = new ArrayList<>();
        for (int i = 0; i < linkList.size(); i++) {
            copyedLinkList.add(linkList.get(i));
        }
        List<TreeInfoDto> finalList = new ArrayList<>();

        TreeInfoDto tree=null;
        while (copyedLinkList.size()>0)
        {
            tree=new TreeInfoDto();
            deviceEntityList = new HashSet<>();
            deviceRecursion(copyedLinkList.get(0),copyedLinkList);
            String treeId = IdUtil.getStringId();
            tree.setId(treeId);
            Iterator<TopoInfoDto> iterator = deviceEntityList.iterator();
            while (iterator.hasNext())
            {
                iterator.next().setTreeId(treeId);
            }
            tree.setTotalNodesOfTree(deviceEntityList);
            finalList.add(tree);
        }
        return finalList;
    }

    /**
     * 确定每个topo树下所有的设备
     * @param
     * @param linkList
     * @return
     */
    public static List<TopoInfoDto> deviceRecursion(LinkInfoDto linkEntity, List<LinkInfoDto> linkList)
    {
        String sourceNodeId = linkEntity.getAneDevice().getId();
        String northNodeId = linkEntity.getZneDevice().getId();

        deviceEntityList.add(linkEntity.getZneDevice());
        deviceEntityList.add(linkEntity.getAneDevice());
        linkList.remove(linkEntity);

        if(linkList.size()>0)
        {
            for(int i=0;i<linkList.size();i++)
            {
                if(linkList.get(i).getAneDevice().getId().equals(sourceNodeId) || linkList.get(i).getZneDevice().getId().equals(sourceNodeId))
                {
                    if(linkList.get(i).getAneDevice().getId().equals(sourceNodeId))
                    {
                        LinkInfoDto link = linkList.get(i);

                        deviceEntityList.add(link.getZneDevice());

                        collectLink.add(link);

                    }else if(linkList.get(i).getZneDevice().getId().equals(sourceNodeId))
                    {
                        LinkInfoDto link = linkList.get(i);

                        deviceEntityList.add(link.getAneDevice());

                        collectLink.add(link);

                    }
                }else if(linkList.get(i).getAneDevice().getId().equals(northNodeId) || linkList.get(i).getZneDevice().getId().equals(northNodeId))
                {
                    if(linkList.get(i).getAneDevice().getId().equals(northNodeId))
                    {
                        LinkInfoDto link = linkList.get(i);

                        deviceEntityList.add(link.getZneDevice());

                        collectLink.add(link);

                    }else if(linkList.get(i).getZneDevice().getId().equals(northNodeId))
                    {
                        LinkInfoDto link = linkList.get(i);

                        deviceEntityList.add(link.getAneDevice());

                        collectLink.add(link);
                    }
                }
            }

            Iterator<LinkInfoDto> it = collectLink.iterator();
            while (it.hasNext())
            {
                linkList.remove(it.next());
            }
            if(collectLink.size()>0 && linkList.size()>0)
            {
                for (int i=0;i<collectLink.size();i++)
                {
                    LinkInfoDto next=collectLink.get(i);
                    collectLink.remove(next);
                    deviceRecursion(next,linkList);
                }
            }else
            {
                return deviceList;
            }
        }
        return deviceList;
    }

    /**
     * 确定层高递归
     * @param device
     * @param flag
     */
    public static void storeyRecursion(TopoInfoDto device, int flag,List<TopoInfoDto> tempDeviceList)//AP 1
    {
        tempDeviceList = tempDeviceList.stream().distinct().collect(Collectors.toList());
        for(int i=0;i<device.getOppositeDeviceList().size();i++)
        {
            for(int j=0;j<deviceList.size();j++)
            {
                if (deviceList.get(j).getId().equals(device.getOppositeDeviceList().get(i)) && !tempDeviceList.contains(deviceList.get(j)))
                {
                    labelDeviceList.add(deviceList.get(j));
                    deviceList.get(j).getStorey().add(Collections.min(device.getStorey())+1);
                    tempDeviceList.add(device);
                }
            }
        }
        flag++;
        if(labelDeviceList.size()>0)
        {
            for(int i=0;i<labelDeviceList.size();i++)
            {
                TopoInfoDto temp = labelDeviceList.get(i);
                labelDeviceList.remove(temp);
                storeyRecursion(temp,flag,tempDeviceList);
            }
        }
    }

    /**
     * 给每个设备确定层高(取最低值)
     */
    public static void confirmStorey()
    {
        for(TopoInfoDto device:deviceList)
        {
            int minStorey = device.getStorey().get(0);
            for(int i=0;i<device.getStorey().size();i++)
            {
                if(device.getStorey().get(i) < minStorey)
                {
                    minStorey = device.getStorey().get(i);
                }
            }
            device.getStorey().clear();
            device.getStorey().add(minStorey);
        }
    }

    public HttpHeaders getHeader(String userName, String password,String domain)
    {
        HttpHeaders requestHeaders = new HttpHeaders();
        String token="";
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        requestHeaders.setContentType(type);
        requestHeaders.add("Accept", MediaType.APPLICATION_JSON.toString());

        try {
            if (redisUtil.exist(userName.concat("token"))) {
                token = redisUtil.getValue(userName.concat("token"));
            } else {
                //获取token
                token = cloudCampusApi.getToken(userName, password, requestHeaders, domain);
                redisUtil.set(userName.concat("token"), 1, token, 10);
            }
            //获取站点
            requestHeaders.add("X-AUTH-TOKEN", token);
        } catch (Exception e) {
            log.error("token Access failure!");
        }
        return requestHeaders;
    }

    /**
     * 获取云平台设备数据
     * @param requestHeaders
     * @param domain
     * @return
     */
    public List<TopoInfoDto> getDevices(HttpHeaders requestHeaders,String domain) {
        //查询设备(默认查询站点下所有设备)
        List<TopoInfoDto> deviceDtos = new ArrayList<>();
        try {
            AtomicBoolean flag = new AtomicBoolean(true);
            AtomicInteger pageIndex = new AtomicInteger(1);
            while (flag.get()) {
                HttpEntity<String> requestEntity = new HttpEntity<>(requestHeaders);
                ResponseEntity<JSONObject> response = restTemplate.exchange("https://"+domain+ DEVICES_URL + "?pageSize=1000&pageIndex=" + pageIndex , HttpMethod.GET, requestEntity, JSONObject.class);
                JSONArray data = response.getBody().getJSONArray("data");
                if (!data.isEmpty()) {
                    deviceDtos.addAll(data.toJavaList(TopoInfoDto.class));
                    pageIndex.getAndIncrement();
                } else {
                    flag.set(false);
                }}
            return deviceDtos;
        } catch (Exception e) {
            log.error("debug getDevices ==>" + e.getMessage());
            return null;
        }
    }
}
